package purchaseStore

import (
	"context"
	"errors"
	"github.com/google/uuid"
	"github.com/kuangshp/go-utils/k"
	"github.com/shopspring/decimal"
	"insighttracking/apps/admin/auth"
	"insighttracking/common/enum"
	"insighttracking/common/utils"
	"insighttracking/query/dao"
	"insighttracking/query/model"
	"insighttracking/query/service"
	"net/http"
	"time"

	"insighttracking/apps/admin/internal/svc"
	"insighttracking/apps/admin/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
	"os"
)

type CreatePurchaseStoreApiLogic struct {
	logx.Logger
	ctx     context.Context
	svcCtx  *svc.ServiceContext
	Request *http.Request
}

func NewCreatePurchaseStoreApiLogic(ctx context.Context, svcCtx *svc.ServiceContext, request *http.Request) *CreatePurchaseStoreApiLogic {
	hostname, _ := os.Hostname()
	return &CreatePurchaseStoreApiLogic{
		Logger: logx.WithContext(ctx).WithCallerSkip(0).WithFields(
			logx.Field("Log_UUID", uuid.New().String()),
			logx.Field("hostname", hostname)),
		ctx:     ctx,
		svcCtx:  svcCtx,
		Request: request,
	}
}

func (l *CreatePurchaseStoreApiLogic) CreatePurchaseStoreApi(req *types.CreatePurchaseStoreReq) (resp string, err error) {
	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return "", err
	}
	var totalCount = decimal.Zero
	var spuIdList = make([]int64, 0)
	for _, item := range req.DataList {
		if req.IsAdd == 1 && item.BatchNumber == "" {
			return "", errors.New("参数错误，补录时，批次号不能为空")
		}
		storeCount, _ := decimal.NewFromString(item.StoreCount)
		purchaserPrice, _ := decimal.NewFromString(item.PurchaserPrice)
		storeAmount, _ := decimal.NewFromString(item.StoreAmount)
		if !storeCount.Mul(purchaserPrice).Equal(storeAmount) {
			return "", errors.New("行内金额错误")
		}
		totalCount = totalCount.Add(storeCount)
		spuIdList = append(spuIdList, item.SpuID)
	}
	tx := dao.Use(l.svcCtx.MysqlDb).Begin()
	// 1.创建主表数据
	purchaseStore := model.PurchaseStoreEntity{
		EnterpriseID:     accountInfo.EnterpriseId,                             // 关联到enterprise表主键id
		PurchaseOrdersID: 0,                                                    // 采购单purchase_orders表主键id,如果是pc创建的时候为0
		OrderNo:          utils.GenerateTodayOrderNo(l.svcCtx.RedisDb, "CGRK"), // 操作流水号
		SupplierID:       req.SupplierID,                                       // 供应商,关联到supplier表主键id
		PurchaserID:      req.PurchaserID,                                      // 采购员,关联到
		OperateDate:      time.Now(),                                           // 收货日期
		OperateID:        req.OperateID,                                        // 制单员id,关联到员工表
		WarehouseID:      req.WarehouseID,                                      // 入库仓,关联到warehouse表主键id
		TotalCount:       totalCount,                                           // 采购总数量
		Source:           1,                                                    // 来源,0表示采购单生成,1表示手动创建单
		Types:            req.Types,                                            // 类型,0表示供应商创建,1表示现场采购
		Status:           enum.PurchaseStoreEnum,                               // 状态,0表示待入库,10表示部分收货,20表示全部收货
		Remark:           req.Remark,                                           // 备注
		CreatedID:        accountInfo.PersonId,                                 // 创建人
		CreatedName:      accountInfo.PersonName,                               // 创建人
	}
	if err = service.PurchaseStoreService.CreatePurchaseStoreApi(l.ctx, tx, &purchaseStore); err != nil {
		if err = tx.Rollback(); err != nil {
			return "", err
		}
		return "", err
	}
	spuEntities, err := service.SpuService.GetSpuByIdListApi(l.ctx, spuIdList)
	var spuMap = make(map[int64]*model.SpuEntity)
	var unitNameMap = make(map[int64]string)
	if err == nil && len(spuEntities) > 0 {
		spuMap = k.ToMap(spuEntities, func(item *model.SpuEntity) (int64, *model.SpuEntity) {
			return item.ID, item
		})
		unitIdList := k.Map(spuEntities, func(item *model.SpuEntity, index int) int64 {
			return item.UnitID
		})
		unitEntities, err := service.UnitService.GetByIdListApi(l.ctx, unitIdList)
		if err == nil && len(unitEntities) > 0 {
			unitNameMap = k.ToMap(unitEntities, func(item *model.UnitEntity) (int64, string) {
				return item.ID, item.Name
			})
		}
	}
	// 2.创建详情表数据
	var detailData = make([]*model.PurchaseStoreDetailEntity, 0)
	myRedisDb := l.svcCtx.RedisDb
	storageTime := time.Now()
	if req.StorageTime != "" {
		storageTime = utils.DateTimeStrToTime(req.StorageTime)
	}

	for _, item := range req.DataList {
		spu, isOk := spuMap[item.SpuID]
		if !isOk {
			continue
		}
		purchaserPrice, _ := decimal.NewFromString(item.PurchaserPrice)
		storeCount, _ := decimal.NewFromString(item.StoreCount)
		purchaserCount, _ := decimal.NewFromString(item.PurchaserCount)
		storeAmount, _ := decimal.NewFromString(item.StoreAmount)
		if storeCount.Compare(purchaserCount) >= 0 {
			storeAmount = purchaserCount.Mul(purchaserPrice)
		} else {
			storeAmount = storeCount.Mul(purchaserPrice)
		}
		unitName := unitNameMap[spu.UnitID]
		// 根据入库时间生成入库批次号
		batchNumber := utils.StorageBatchNumber(myRedisDb, storageTime, item.SpuID, "RKPC")
		// 补录时，批次号从入参获取
		if req.IsAdd == 1 {
			batchNumber = item.BatchNumber
		}
		detailData = append(detailData, &model.PurchaseStoreDetailEntity{
			PurchaseStoreID:         purchaseStore.ID,                   // 采购入库单purchase_store表主键id
			SpuID:                   item.SpuID,                         // 商品,关联到spu表主键id
			SnapshotSpuName:         spu.Name,                           // 快照商品名称
			SnapshotProductImageURL: spu.ProductImageURL,                // 快照产品图片
			SnapshotSpuType:         spu.SpuType,                        // 快照商品类型,0表示基础商品,1表示加工商品
			SnapshotUnit:            unitName,                           // 快照单位
			SnapshotCategoryID:      spu.CategoryID,                     // 快照分类id
			SnapshotCategory:        spu.CategoryName,                   // 快照分类
			SnapshotPrice:           spu.SalesPrice,                     // 快照商品单价
			LossRate:                spu.LossRate,                       // 快照损耗率
			PurchaserPrice:          purchaserPrice,                     // 采购单价
			PurchaserCount:          purchaserCount,                     // 采购数量
			PurchaserAmount:         purchaserPrice.Mul(purchaserCount), // 采购金额
			StoreCount:              storeCount,                         // 入库数量
			StoreAmount:             storeAmount,                        // 入库金额
			StoreStatus:             enum.PurchaseStoreEnum,             // 入库状态,0表示待入库,10表示部分入库,20表示全部入库
			Remark:                  item.Remark,                        // 备注
			ShelfID:                 item.ShelfID,                       // 货架ID
			StorageTime:             storageTime,                        // 入库时间
			BatchNumber:             batchNumber,
		})
		// 3.商品当前库存
		if err = service.SpuInventoryService.IncrInventoryApi(l.ctx, tx, accountInfo.EnterpriseId, req.WarehouseID, item.SpuID, storeCount); err != nil {
			if err = tx.Rollback(); err != nil {
				return "", err
			}
			return "", errors.New("创建失败")
		}
		// 4.货架当前库存
		if _, err = service.SpuShelfGridInventoryService.IncrGridInventoryApi(l.ctx, tx, accountInfo.EnterpriseId, item.ShelfID, item.SpuID, req.SupplierID, item.ExpirationDate, batchNumber, storeCount); err != nil {
			if err = tx.Rollback(); err != nil {
				return "", err
			}
			return "", errors.New("创建失败")
		}

		// 库存记录
		if err = service.InventRecordService.CreateInventRecordApi(l.ctx, tx, &model.InventoryRecordEntity{
			EnterpriseID: accountInfo.EnterpriseId,       // 关联到enterprise表主键id
			SpuID:        item.SpuID,                     // 商品主键,关联到spu表主键id
			Types:        0,                              // 类型,0表示入库,1表示出库
			Source:       0,                              // 来源,0表示正常出入口,10表示盘点报损报溢,20表调拨
			WarehouseID:  purchaseStore.WarehouseID,      // 仓库id,关联到warehouse表主键id
			ChangeCount:  storeCount,                     // 变动数量
			Price:        spu.SalesPrice,                 // 单价
			Amount:       storeCount.Mul(spu.SalesPrice), // 金额
			ShelfID:      item.ShelfID,                   // 货架ID
			BatchNumber:  batchNumber,                    // 批次号
		}); err != nil {
			if err = tx.Rollback(); err != nil {
				return "", err
			}
			return "", errors.New("操作失败")
		}
	}
	if err = service.PurchaseStoreDetailService.CreateBatchApi(l.ctx, tx, detailData); err != nil {
		if err = tx.Rollback(); err != nil {
			return "", err
		}
		return "", errors.New("创建失败")
	}
	if err = tx.Commit(); err != nil {
		return "", errors.New("创建失败")
	}
	return "操作成功", nil
}
